package cn.jobstart.common;

import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
import sun.misc.BASE64Decoder;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
* @Description: （密钥工具类） 
* @author: Felix  
* @date: 2019年5月11日下午2:04:21
 */
@Slf4j
public class RsaUtil {
    /** 指定加密算法为RSA */
    private static final String  ALGORITHM         = "RSA";

    private static final String  ALGORITHMPHP      = "RSA/ECB/PKCS1Padding";

    private static final int     MAX_DECRYPT_BLOCK = 256;

    /** 密钥长度，用来初始化 */
    private static final int     KEYSIZE           = 1024;

    public static final String   CHARSET           = "UTF-8";

    private static RSAPublicKey  publicKey;

    private static RSAPrivateKey privateKey;

    /**
     * 生成密钥对
     * @return
     */
    public static Map<String, String> createKeys() {

        // /** RSA算法要求有一个可信任的随机数源 */
        //		 SecureRandom secureRandom = new SecureRandom();

        /** 为RSA算法创建一个KeyPairGenerator对象 */
        KeyPairGenerator keyPairGenerator = null;
        try {
            keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        /** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
        //		 keyPairGenerator.initialize(KEYSIZE, secureRandom);
        keyPairGenerator.initialize(KEYSIZE);

        /** 生成密匙对 */
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        /** 得到公钥 */
        Key publicKey = keyPair.getPublic();

        /** 得到私钥 */
        Key privateKey = keyPair.getPrivate();
        String publicKeyStr = Base64.getEncoder().encodeToString(publicKey.getEncoded());
        String privateKeyStr = Base64.getEncoder().encodeToString(privateKey.getEncoded());
        System.out.println("publicKeyStr:" + publicKeyStr);
        System.out.println("privateKeyStr:" + privateKeyStr);
        Map<String, String> keyPairMap = new HashMap<String, String>();
        keyPairMap.put("publicKey", publicKeyStr);
        keyPairMap.put("privateKey", privateKeyStr);
        return keyPairMap;
    }

    /**
     * 初始化公钥
     * @param publicKeyStr
     * @return
     */
    public static RSAPublicKey initPublicKey(String publicKeyStr) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
            //通过X509编码的Key指令获得公钥对象
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyStr));
            publicKey = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
            return publicKey;
        } catch (Exception e) {
            throw new RuntimeException("不支持的密钥", e);
        }
    }

    /**
     * 初始化私钥
     * @param privateKeyStr
     * @return
     */
    public static RSAPrivateKey initPrivateKey(String privateKeyStr) {
        try {
            BASE64Decoder base64Decoder = new BASE64Decoder();
            byte[] buffer = base64Decoder.decodeBuffer(privateKeyStr);
            RSAPrivateKeyStructure asn1PrivKey = new RSAPrivateKeyStructure((ASN1Sequence) ASN1Sequence.fromByteArray(buffer));
            RSAPrivateKeySpec rsaPrivKeySpec = new RSAPrivateKeySpec(asn1PrivKey.getModulus(), asn1PrivKey.getPrivateExponent());
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
            PrivateKey priKey = keyFactory.generatePrivate(rsaPrivKeySpec);
            return (RSAPrivateKey) priKey;
        } catch (Exception e) {
            throw new RuntimeException("不支持的密钥", e);
        }
    }

    /**
     * 公钥加密
     * @param data
     * @param publicKey
     * @return
     */
    public static String publicEncrypt(String data, RSAPublicKey publicKey) {

        try {
            return encryptByPublic(data.getBytes(), publicKey);
            ////        	initRsaKey();
            //            Cipher cipher = Cipher.getInstance(ALGORITHM);
            //            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            //            return Base64.getEncoder().encodeToString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength()));
        } catch (Exception e) {
            log.error("公钥加密异常", e);
        }
        return null;
    }

    /**
     * RSA公钥加密
     * @param content 等待加密的数据
     * @param publicKey RSA 公钥 if null then getPublicKey()
     * @return 加密后的密文(16进制的字符串)
     */
    public static String encryptByPublic(byte[] content, PublicKey publicKey) {

        if (publicKey == null) {
        }
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            // 该密钥能够加密的最大字节长度
            int splitLength = ((RSAPublicKey) publicKey).getModulus().bitLength() / 8 - 11;
            byte[][] arrays = splitBytes(content, splitLength);
            StringBuffer stringBuffer = new StringBuffer();
            for (byte[] array : arrays) {
                stringBuffer.append(bytesToHexString(cipher.doFinal(array)));
            }
            return stringBuffer.toString();
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * 根据限定的每组字节长度，将字节数组分组
     * @param bytes 等待分组的字节组
     * @param splitLength 每组长度
     * @return 分组后的字节组
     */
    public static byte[][] splitBytes(byte[] bytes, int splitLength) {
        // bytes与splitLength的余数
        int remainder = bytes.length % splitLength;
        // 数据拆分后的组数，余数不为0时加1
        int quotient = remainder != 0 ? bytes.length / splitLength + 1 : bytes.length / splitLength;
        byte[][] arrays = new byte[quotient][];
        byte[] array = null;
        for (int i = 0; i < quotient; i++) {
            // 如果是最后一组（quotient-1）,同时余数不等于0，就将最后一组设置为remainder的长度
            if (i == quotient - 1 && remainder != 0) {
                array = new byte[remainder];
                System.arraycopy(bytes, i * splitLength, array, 0, remainder);
            } else {
                array = new byte[splitLength];
                System.arraycopy(bytes, i * splitLength, array, 0, splitLength);
            }
            arrays[i] = array;
        }
        return arrays;
    }

    /**
     * 将字节数组转换成16进制字符串
     * @param bytes 即将转换的数据
     * @return 16进制字符串
     */
    public static String bytesToHexString(byte[] bytes) {
        StringBuffer sb = new StringBuffer(bytes.length);
        String temp = null;
        for (int i = 0; i < bytes.length; i++) {
            temp = Integer.toHexString(0xFF & bytes[i]);
            if (temp.length() < 2) {
                sb.append(0);
            }
            sb.append(temp);
        }
        return sb.toString();
    }

    /**
     * 行家联盟公钥加密
     * @param data
     * @param publicKey
     * @return
     */
    public static String publicEncryptHJLM(String data, RSAPublicKey publicKey) {
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            return Base64.getEncoder().encodeToString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * RSA公钥加密
     * @param cipher
     * @param opmode
     * @param datas
     * @param keySize
     * @return
     */
    private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) {
        int maxBlock = 0;
        if (opmode == Cipher.DECRYPT_MODE) {
            maxBlock = keySize / 8;
        } else {
            maxBlock = keySize / 8 - 11;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] buff;
        int i = 0;
        try {
            while (datas.length > offSet) {
                if (datas.length - offSet > maxBlock) {
                    buff = cipher.doFinal(datas, offSet, maxBlock);
                } else {
                    buff = cipher.doFinal(datas, offSet, datas.length - offSet);
                }
                out.write(buff, 0, buff.length);
                i++;
                offSet = i * maxBlock;
            }
        } catch (Exception e) {
            e.printStackTrace();
            //	            throw new RuntimeException("加解密阀值为["+maxBlock+"]的数据时发生异常", e);
        }
        byte[] resultDatas = out.toByteArray();
        IOUtils.closeQuietly(out);
        return resultDatas;
    }

    /**
     * 私钥解密
     * @param data
     * @param privateKey
     * @return
     */
    public static String privateDecrypt(String data, RSAPrivateKey privateKey) {
        try {
            return decryptByPrivate(data, privateKey);
        } catch (Exception e) {
            log.error("私钥解密异常", e);
        }
        return null;
    }

    /**
     * RSA私钥解密
     *
     * @param content 等待解密的数据
     * @param privateKey RSA 私钥 if null then getPrivateKey()
     * @return 解密后的明文
     */
    public static String decryptByPrivate(String content, PrivateKey privateKey) {
        if (privateKey == null) {
            //privateKey = getPrivateKey();
        }
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            // 该密钥能够加密的最大字节长度
            int splitLength = ((RSAPrivateKey) privateKey).getModulus().bitLength() / 8;
            byte[] contentBytes = hexStringToBytes(content);
            byte[][] arrays = splitBytes(contentBytes, splitLength);
            StringBuffer stringBuffer = new StringBuffer();
            for (byte[] array : arrays) {
                stringBuffer.append(new String(cipher.doFinal(array)));
            }
            return stringBuffer.toString();
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * 将16进制字符串转换成字节数组
     * @param hex 16进制字符串
     * @return byte[]
     */
    public static byte[] hexStringToBytes(String hex) {

        int len = (hex.length() / 2);
        hex = hex.toUpperCase();
        byte[] result = new byte[len];
        char[] chars = hex.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (toByte(chars[pos]) << 4 | toByte(chars[pos + 1]));
        }
        return result;
    }

    /**
     * 将char转换为byte
     * @param c char
     * @return byte
     */
    private static byte toByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    /**
     * 行家联盟私钥解密
     * @param data
     * @param privateKey
     * @return
     */
    public static String privateDecryptHJLM(String data, RSAPrivateKey privateKey) {
        try {
            Cipher c1 = Cipher.getInstance(ALGORITHM);
            c1.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] temp = c1.doFinal(base64decode(data));
            return new String(temp);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * base64解密
     * @param str
     * @return byte[]
     */
    @SuppressWarnings("restriction")
    private static byte[] base64decode(String str) {
        byte[] bt = null;
        try {
            BASE64Decoder decoder = new BASE64Decoder();
            bt = decoder.decodeBuffer(str);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bt;
    }


    public static void main(String[] args) throws Exception {

       /* // 公钥加密的数据
        String data = "5c0e7d9edde1650bbbb1ca50848f637f44ded9f747bd512a4ac3f525a70c0c0a954635636b8e891fef517e1f5a59c3d4ef7e11601e3fb9b5bd2f7e20f8734a0be0963bf6e01536a9c6ce6232b48c858f189999d3d220f89b46cccf7badc7ff90beff80d08945f3fda004995cc869165e7fc92fc04b0e3296fd5adf2b1c369558ebbad41463aaa6b101189c719f4898f07ce846e7b9fe22ee94d72d809d51dea6fbb37f6eb773b7109927b8a284b1d5a2f1de638531447d39028ff8fbbffd19a332b2bd6d470143a03b1b0e515b92155415f0d13b7640b20e1bcd8a033ba766aae0e2022d236f90e225d6f193559bf60c009da3d8420a33ebeb3bfad868b6dc13dd7136b9cbef89e0da39300dea55f21227152e806a3099da215502abd0b22e23ae0850c77adb147b69c52a842e8f08dd173d40ed346fe18608c4e7d2cacd9c114e2e786efb5b9b428a96d8dd610f082c5bf13e7638b99077f8b720a0c7c3f0d078ecacd28ff1e696d966243ee1d9361291adac72c30ef902321c9a71c9156e88304eb8c8fdd516a8fc8226ef29662243ba7b6d5564fbb122f0659f3c9f623ca5f30d4f8fe3aafcdf79d9e609228b83dfb62faa0ff6947892497ffab879c727cebf4b85d9eb434ecfdfa41a55030deeb919789318cc0de1b8c06a4fcb0e1f621fbcad66a1265139c8fa8dcd4ca0d2b3729b3d8afefa29719cc67684b9382fd109";



        // 私钥
        String privateKey = "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";
        // 私钥解密数据
        String result = RsaUtil.decryptByPrivate(data, RsaUtil.initPrivateKey(privateKey));
        System.out.println("result:" + result);

        String pubKey=
                "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKSG9cwJRmv9vTnWPLzTE0pxJ+2sj+rJzoBe1pCyTvmed/wqSD4qp99m8fWqBzNMjNrvPo5RK6lVRfDppYqRVt0CAwEAAQ==";
        privateKey="MIICXQIBAAKBgQCnDtsVYxXXtfBn4cRo50mALBPIEitNl5EL9+ksYfgAUqqSX4Ql" +
                "+bDtpggfzTBoLuyebpnDSPn71KjWeB1Q+3/PMq5sV+ohPv5Ii8kmuy6AZPm6sI0j" +
                "AtNqKXKKciwoVxmsejBg6gOopBTyaYLxB//DB2cHZejnqFlM5Lb/gW1MWQIDAQAB" +
                "AoGBAJ8617NA6FbcwbIiTNU4bqROXuR5/PBOISBpQcTd9EZKhO5TQF/56Jv7fw7g" +
                "wtzqrPotrT2n1y4jenJBtp+zuBM5j05s4xjHtwXTLchRjM+YYXAsfvwHubjFjuB9" +
                "I3XS0dt/vgQ4VgZR/KBf61k3Hs76KVPO4bXPn8C1YsFQC3gBAkEA0nzpQiyLU3IH" +
                "QauHp6UdTowE6GPdIySoDP2FlSSJobxxm9UAHqHREzKW4b7dM0YExmzOqONXraLx" +
                "gOpD2MtegQJBAMst+rxs+6a2/kZBvK9F4FdMnmOzX3fohlynONyWXZQHzh6egduH" +
                "OTGlSt1c2LuJqY/d+g0NziLFLMFp580zsdkCQBrHjZ2/sRIyxb2TJzUrCql9ovo2" +
                "CmJ4PXE5qA8rkN8k7IdY+CTtjX4Vx6B8+gOV+vGL0lcmZXdP7c3rACrK5QECQDo3" +
                "UHKQ34IjSLQkvcWSxfb9kxyKFr6qt2Tw3RAHXYS+v8ZyME8QbcjVzZ+jrM3/YcBB" +
                "IBaBcCDyUiKRD8PyHfECQQCw6W29imY9Sab6A4D5McBQ6Fx++WXdTEI8GeEUR8Us" +
                "vwFk1JEexyNOaiGqVFaTE8xK+vCrO/QA0RlGHJGHxgoz";

        String sourceData="{a:ss}";

        data=RsaUtil.publicEncrypt(sourceData,RsaUtil.initPublicKey(pubKey));

        System.out.println(RsaUtil.decryptByPrivate(data,RsaUtil.initPrivateKey(privateKey)));*/


      /* String password="FTYtItOMh1ku74ROgCman5xR+y7Pc98N8m3HI6VuKFTbV23sCbINLoExC2XRV5gR/Ar6ve/FWcn8oavhUBjP1w==";
        String publicKey ="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKSG9cwJRmv9vTnWPLzTE0pxJ+2sj+rJzoBe1pCyTvmed/wqSD4qp99m8fWqBzNMjNrvPo5RK6lVRfDppYqRVt0CAwEAAQ==";
        password = ConfigTools.decrypt(publicKey, password);

        System.out.println(password);*/



    }
}
